package com.hjb.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.hjb.entity.Database;
import com.hjb.util.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.alibaba.druid.pool.DruidDataSourceFactory.*;

/**
 * @author HuJiaBing
 * @date 2025/7/3 17:53
 * @description
 */
@Slf4j
public class DynamicDatasource extends AbstractRoutingDataSource {

    private static final String INITIAL_SIZE = "1";
    private static final String MAX_ACTIVE = "5";
    private static final String MIN_IDLE = "1";
    private static final String MAX_WAIT = "3000";
    private static final String TIME_BETWEEN_EVICTION_RUNS_MILLIS = "10000";
    private static final String MIN_EVICTABLE_IDLE_TIME_MILLIS = "60000";
    private static final String TEST_WHILE_IDLE = "true";
    private static final String TEST_ON_BORROW = "false";
    private static final String TEST_ON_RETURN = "false";
    private static final String REMOVE_ABANDONED = "true";
    private static final String MAX_POOL_PREPARED_STATEMENT_PER_CONNECTION_SIZE = "20";
    private static final String VALIDATIONQUERY_TIMEOUT = "5000";
    private static final String PROP_VALIDATIONQUERY = "select * from mysql limit 1";

    private final static Map<Object, Object> dataSourceMap = new HashMap<>();

//    private DataSource primaryDataSource;
//
//    public void setPrimaryDataSource(DataSource primaryDataSource) {
//        this.primaryDataSource = primaryDataSource;
//    }
//
//    public DataSource getPrimaryDataSource() {
//        return primaryDataSource;
//    }

    public static Map<Object, Object> getDataSourceMap() {
        return dataSourceMap;
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return DatasourceRouteKeyHolder.getDataSourceRouteKey();
    }

    public static DataSource init(Database database, boolean cache) {
        Map<String, String> param = buildDataSourceInitProperties(database);
        try {
            DruidDataSource dataSource = (DruidDataSource)createDataSource(param);
            if (cache) {
                dataSourceMap.put(database.getId(), dataSource);
                refreshDatasource();
            }
            return dataSource;
        } catch (Exception e) {
            log.error("初始化数据源失败, databaseId:【{}】", database.getId(), e);
        }
        return null;
    }

    public static void batchInit(List<Database> databases) {
        for (Database database : databases) {
            init(database, true);
        }
    }

    private static Map<String, String> buildDataSourceInitProperties(Database database) {
        HashMap<String, String> param = new HashMap<>();
        param.put(PROP_DRIVERCLASSNAME, database.getDriverClassName());
        param.put(PROP_URL, "jdbc:mysql://" + database.getHost() +":"+ database.getPort() + "/"+ database.getDbName() + "?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai");
        param.put(PROP_USERNAME, database.getUsername());
        param.put(PROP_PASSWORD, database.getPassword());
        param.put(PROP_INITIALSIZE, INITIAL_SIZE);
        param.put(PROP_MAXACTIVE, MAX_ACTIVE);
        param.put(PROP_MINIDLE, MIN_IDLE);
        param.put(PROP_MAXWAIT, MAX_WAIT);
        param.put(PROP_TIMEBETWEENEVICTIONRUNSMILLIS, TIME_BETWEEN_EVICTION_RUNS_MILLIS);
        param.put(PROP_MINEVICTABLEIDLETIMEMILLIS, MIN_EVICTABLE_IDLE_TIME_MILLIS);
        param.put(PROP_TESTWHILEIDLE, TEST_WHILE_IDLE);
        param.put(PROP_TESTONBORROW, TEST_ON_BORROW);
        param.put(PROP_TESTONRETURN, TEST_ON_RETURN);
        param.put(PROP_POOLPREPAREDSTATEMENTS, MAX_POOL_PREPARED_STATEMENT_PER_CONNECTION_SIZE);
        param.put(PROP_REMOVEABANDONED, REMOVE_ABANDONED);
        param.put(PROP_VALIDATIONQUERY, null);
        param.put(PROP_VALIDATIONQUERY_TIMEOUT, VALIDATIONQUERY_TIMEOUT);
        return param;
    }

    private static void refreshDatasource() {
        DynamicDatasource dynamicDatasource = SpringUtil.getBean(DynamicDatasource.class);
        dynamicDatasource.afterPropertiesSet();
    }

}
